package com.prj.ufdm.file.api;

import java.io.BufferedInputStream;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.prj.ufdm.file.enums.MSFileConstants;
import com.prj.ufdm.file.enums.UpFileRetCodeEnum;
import com.prj.ufdm.file.enums.WholeFileStatusEnum;
import com.prj.ufdm.file.model.AloneFile;
import com.prj.ufdm.file.model.WholeFile;
import com.prj.ufdm.file.service.AloneFileService;
import com.prj.ufdm.file.service.WholeFileService;
import com.prj.ufdm.core.dto.RetData;
import com.prj.ufdm.core.exception.BaseException;

@RestController
@RequestMapping("/api/file/")
public class FileUploadApi {

	@Autowired
	private AloneFileService aloneFileService;
	
	@Autowired
	private WholeFileService wholeFileService;

	/**
	 * 获取大文件上传wholeID
	 * @param fileName
	 * @param aliases
	 * @param fileType
	 * @param fileHash
	 * @param fileSize
	 * @param chunkSize
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/crewfid")
	public RetData<WholeFile> createWholeFile(WholeFile wholeFile) throws Exception {
		RetData<WholeFile> retWholeFile = new RetData<WholeFile>();
		retWholeFile.setRetBody(wholeFileService.createWholeFile(wholeFile));
		return retWholeFile; 
	}
	
	/**
	 * 获取大文件上传wholeID
	 * @param file
	 * @param aliases
	 * @param chunkSize
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/crewfidbwf")
	public RetData<WholeFile> getWholeFileIdByWholeFile(MultipartFile file,String aliases,String chunkSize) throws Exception {
		
		System.out.println("\n action aliases:"+aliases);
		
		System.out.println("\n action chunkSize:"+chunkSize);
		
		RetData<WholeFile> retWholeFile = new RetData<WholeFile>();
		WholeFile wholeFile = new WholeFile();
		if(file==null || file.getSize()<1) {
			throw new BaseException(UpFileRetCodeEnum.RET_CODE_0401011.getCode(),UpFileRetCodeEnum.RET_CODE_0401011.getMessage());
		}
		wholeFile.setFileHash(DigestUtils.md5Hex(file.getInputStream()));
		wholeFile.setFileName(file.getOriginalFilename().lastIndexOf(".")!=-1 ? file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf(".")) : file.getOriginalFilename());
		if(wholeFile.getAliases()==null || wholeFile.getAliases().equals("")) {
			wholeFile.setAliases(file.getOriginalFilename().lastIndexOf(".")!=-1 ? file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf(".")) : file.getOriginalFilename());
		}
		wholeFile.setFileSize(String.valueOf(file.getSize()));
		wholeFile.setChunkSize(chunkSize);
		wholeFile.setFileType(file.getOriginalFilename().lastIndexOf(".")!=-1 ? file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1) : MSFileConstants.DEFAULT_FILE_TYPE);
		wholeFile.setContentType(file.getContentType());
		
		MathContext mc = new MathContext(10, RoundingMode.HALF_UP);
		BigDecimal bigFileSize = new BigDecimal(file.getSize());
		BigDecimal bigChunkSize = new BigDecimal(chunkSize);
		int chunkCount = (int) Math.ceil(bigFileSize.divide(bigChunkSize, mc).doubleValue()) ;
		wholeFile.setChunkCount(String.valueOf(chunkCount));
		retWholeFile.setRetBody(wholeFileService.createWholeFile(wholeFile));
		return retWholeFile; 
	}
	
	/**
	 * DESC: 文件上传
	 * @param file 
	 * @param aliases
	 * @param wholeFileId 大文件ID
	 * @param chunkNum
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/upload")
	public RetData<AloneFile> uploadFile(MultipartFile file,String aliases,String wholeFileId,String chunkNum) throws Exception {
		
		long time1 = new Date().getTime();
		System.out.println("\n *********----接收到请求（开始获取HASH）："+time1);
		RetData<AloneFile> retAloneFile = new RetData<AloneFile>();
		AloneFile aloneFile = new AloneFile();
		if(file==null || file.getSize()<1) {
			throw new BaseException(UpFileRetCodeEnum.RET_CODE_0401011.getCode(),UpFileRetCodeEnum.RET_CODE_0401011.getMessage());
		}
		String fileHash = DigestUtils.md5Hex(file.getInputStream());
		
		long time2 = new Date().getTime();
		
		System.out.println("\n 获取HASH耗时（开始验证文件是否存在）:"+(time2-time1));
		
		AloneFile existAloneFile = aloneFileService.getAloneFileByFileHash(fileHash);
		
		long time3 = new Date().getTime();
		
		System.out.println("\n 验证文件耗时（开始上传）:"+(time3-time2));
		
		
		// 判断文件是否存在，不存在，新保存一个
		if(existAloneFile==null) {
			
			System.out.println("\n ");
			
			aloneFile.setAliases(aliases);
			aloneFile = aloneFileService.saveAloneFile(file,aloneFile);
		}
		else {
			
			System.out.println("\n 秒传");
			aloneFile = existAloneFile;
		}
		
        long time4 = new Date().getTime();
		
		System.out.println("\n 文件上传耗时（开始大文件处理）:"+(time4-time3));
		
		
		// 大文件上传
		if(wholeFileId!=null && !wholeFileId.equals("")) {
			wholeFileService.updateWholeFile(wholeFileId, chunkNum, aloneFile);
		}
		
        long time5 = new Date().getTime();
		
		System.out.println("\n 大文件处理耗时:"+(time5-time4));
		
		System.out.println("\n 总共耗时:"+(time5-time1));
		
		retAloneFile.setRetBody(aloneFile);
		return retAloneFile;
	}

	/**
	 * Desc: 监测HASH是否存在
	 * @param fileHash
	 * @return
	 * @throws Exception
	 * Date: 2019年8月1日
	 * Author: Administrator
	 */
	@RequestMapping("/check")
	public RetData<Boolean> checkAloneFile(String fileHash,String wholeFileId,String chunkNum) throws Exception {
		RetData<Boolean> retExist = new RetData<Boolean>();
		if(fileHash==null || fileHash.equals("")) {
			throw new BaseException(UpFileRetCodeEnum.RET_CODE_0401009.getCode(),UpFileRetCodeEnum.RET_CODE_0401009.getMessage());
		}
		System.out.println("\n fileHash:"+fileHash);
		AloneFile existAloneFile = aloneFileService.getAloneFileByFileHash(fileHash);
		System.out.println("\n existAloneFile:"+existAloneFile);
		
		if(existAloneFile!=null && existAloneFile.getFileHash()!=null && !existAloneFile.getFileHash().equals("")) {
			retExist.setRetBody(true);
		}
		else {
			retExist.setRetBody(false);
		}
		// 如果已上传的文件存在
		if(wholeFileId!=null && !wholeFileId.equals("") && existAloneFile!=null ) {
			wholeFileService.updateWholeFile(wholeFileId, chunkNum, existAloneFile);
		}
		return retExist;
	}
	
	/**
	 * DESC: 文件下载
	 * @param fileHashOrWholeFileId  
	 *        单个文件Hash值（AloneFile fileHhash）
	 *        整个文件ID（WholeFile id）
	 *        整个文件Hash值（WholeFile fileHhash）
	 * @return
	 */
	@GetMapping("/downloadFile/{fileHashOrWholeFileId}")
	public void downloadFile(@PathVariable String fileHashOrWholeFileId, HttpServletResponse response) throws Exception {

		// 文件名
		String fileName = "";
		// 文件类型
		String fileType = "";
		// 文件长度
		String fileLength = "";
		
		List<GridFsResource> listGridFsResource = new ArrayList<GridFsResource>();
		// 根据单个文件 hash 值查询
		AloneFile aloneFile = aloneFileService.getAloneFileByFileHash(fileHashOrWholeFileId);
		
		// 判断是否为单个文件的HASH
		if(aloneFile!=null && aloneFile.getFileId()!=null && !aloneFile.getFileId().equals(""))
		{
			fileName = aloneFile.getAliases();
			fileType = aloneFile.getFileType();
			fileLength = aloneFile.getFileSize();
			listGridFsResource.add(aloneFile.getGridFsResource());
		}
		else {
			// 判断是否为 WholeFile 的 ID
			WholeFile wholeFile = wholeFileService.getWholeFileByWholeFileId(fileHashOrWholeFileId);
			if(wholeFile!=null && wholeFile.getId()!=null && !wholeFile.getId().equals("") && WholeFileStatusEnum.WHILE_FILE_STATUS_1.getCode().equals(wholeFile.getFileStatus())) {
				fileName = wholeFile.getAliases();
				fileType = wholeFile.getFileType();
				fileLength = wholeFile.getFileSize();
				listGridFsResource = aloneFileService.getAllGridFsResourceByWholeFileId(fileHashOrWholeFileId);
			}
			else {
				// 判断是否为 WholeFile 的 Hash
				wholeFile = wholeFileService.getWholeFileByWholeFileHash(fileHashOrWholeFileId);
				if( wholeFile!=null && wholeFile.getId()!=null && !wholeFile.getId().equals("") && WholeFileStatusEnum.WHILE_FILE_STATUS_1.getCode().equals(wholeFile.getFileStatus())) {
					fileName = wholeFile.getAliases();
					fileType = wholeFile.getFileType();
					fileLength = wholeFile.getFileSize();
					listGridFsResource = aloneFileService.getAllGridFsResourceByWholeFileHash(fileHashOrWholeFileId);
				}
			}
		}
		
		// 输出文件
		ServletOutputStream outputStream = response.getOutputStream();
		if (listGridFsResource != null && listGridFsResource.size() > 0) {
			if(fileType!=null && !fileType.equals("")) {
				response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(fileName+"."+fileType, "utf-8"));
			}
			else {
				response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
			}
			response.setHeader("Access-Control-Allow-Origin", "*");
			response.setHeader("Cache-Control","no-cache"); 
			response.setHeader("Content-Length", fileLength );
			byte[] buffer = new byte[1024];
			for (GridFsResource gridFsResource : listGridFsResource) {
				BufferedInputStream buffInputStream = null;
				try {
					int count;
					buffInputStream = new BufferedInputStream(gridFsResource.getInputStream());
					while ((count = buffInputStream.read(buffer)) > 0) {
						outputStream.write(buffer, 0, count);
					}
				}
				catch(Exception er) {
					er.printStackTrace();
					responseErrmessage(response,outputStream,"读取文件出现异常："+er);
				}
				finally {
					if(buffInputStream!=null) buffInputStream.close();
				}
			}
		} else {
			responseErrmessage(response,outputStream,"文件不存在");
		}
	}

	void responseErrmessage(HttpServletResponse response,ServletOutputStream outputStream,String message) throws Exception {
		response.setHeader("content-type", "text/html;charset=UTF-8");
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Cache-Control","no-cache"); 
		outputStream.write(message!=null ? message.getBytes("UTF-8") : "".getBytes());
	}
	
	

}
